#include "gui/Viewport.h"

#include "gui/GUIEngine.h"
#include "gui/layers/MapLayer.h"
#include "gui/layers/InfoLayer.h"
#include "util/events/CarMoveEvent.h"
#include "util/MathUtils.h"

namespace gui {

class CarMoveEventViewportListener : public EventListener {
public:
	CarMoveEventViewportListener(Viewport* viewport): EventListener(CarMove_Event) { this->viewport = viewport; }
	~CarMoveEventViewportListener() {}
	void execute(Event* event) {
		CarMoveEvent* carMoveEvent = (CarMoveEvent*)event;
		this->viewport->update(carMoveEvent->getCar()->getPosition());
	}
private:
	Viewport* viewport;
};

Viewport::Viewport(CarController* carController, Layer* background, Layer* foreground, int viewportW, int viewportH, double xScale, double yScale) {
	carController->addEventListener(new CarMoveEventViewportListener(this));
	this->background = background;
	this->foreground = foreground;
	this->portionToDraw.w = util::doubleToInt(viewportW / xScale);
	this->portionToDraw.h = util::doubleToInt(viewportH / yScale);
	this->update(carController->getCarPosition());
	this->screenPortion.x = 0;
	this->screenPortion.y = 0;
	this->screenPortion.w = viewportW;
	this->screenPortion.h = viewportH;
}

Viewport::~Viewport() { }

Surface* Viewport::getPlainSurface(){
	Surface* plainSurface = this->background->getPortion(this->portionToDraw);

	Surface* aux = NULL;
	util::LinkedList<Layer>::Iterator it = this->middleLayers.iterator();
	while(it.hasNext()) {
		aux = it.next()->getPortion(this->portionToDraw);
		plainSurface->applySurface(aux);
		delete aux;
	}
	this->applyScale(plainSurface);

	aux = this->foreground->getPortion(this->screenPortion);
	plainSurface->applySurface(aux, this->screenPortion);
	delete aux;

	return plainSurface;
}

void Viewport::applyScale(Surface* surface) {
	surface->resize(this->screenPortion.w, this->screenPortion.h);
}

void Viewport::update(MapPoint newPortionPosition) {
	// Actualizo el centro del portion to draw.
	this->portionToDraw.x = gui::toPixels(newPortionPosition.getX()) - this->portionToDraw.w / 2;
	this->portionToDraw.y = gui::toPixels(newPortionPosition.getY()) - this->portionToDraw.h / 2;
}

}
